<!--
 * @Author: 王坤
 * @LastEditors: Please set LastEditors
 * @Description: 手机号
-->
<template>
  <div class="lc-phone-number" ref="phoneNumberRef">
    <div
      v-if="magnify && showMagnify && phoneNumberModel"
      :class="{
        'lc-phone-number__magnify': true,
        'lc-phone-number__magnify-bottom': magnifyBottom
      }"
    >
      <span class="lc-phone-number__magnify__text">{{ phoneNumberModel }}</span>
    </div>
    <div class="lc-phone-number__wrap">
      <div class="lc-phone-number__content">
        <div v-if="globalization" class="lc-phone-number__content__area">
          <el-select v-model="phoneArea">
            <el-option
              v-for="item in areaOpts"
              :key="item.value"
              :label="item.label.split(' ')[1]"
              :value="item.value"
            >
              {{ item.label }}
            </el-option>
          </el-select>
        </div>
        <div :class="{ 'lc-phone-number__content__globalization': globalization }">
          <el-input
            v-model="phoneNumberModel"
            :placeholder="placeholder"
            v-bind="$attrs"
            @blur="handleBlur"
            @focus="handleFocus"
          />
        </div>
      </div>
    </div>
    <p v-if="phoneNumberModel && validMessage" class="lc-phone-number__error-message">
      {{ errorNotice }}
    </p>
  </div>
</template>

<script setup>
import { PhoneNumberUtil } from 'google-libphonenumber';
import { computed, ref, unref, watch, onMounted } from 'vue';
const props = defineProps({
  modelValue: {
    type: String,
    default: ''
  },
  //是否国际化
  globalization: {
    type: Boolean,
    default: false
  },
  //是否放大展示
  magnify: {
    type: Boolean,
    default: false
  },
  //输入提示语
  placeholder: {
    type: String,
    default: ''
  },
  // 国际区号列表
  areaOpts: {
    type: Array,
    default: () => [
      {
        label: '中国 +86',
        value: '+86'
      },
      {
        label: '美国 +1',
        value: '+1'
      },
      {
        label: '日本 +81',
        value: '+81'
      }
    ]
  },
  errorNotice: {
    type: String,
    default: '手机号格式错误'
  }
});
const emits = defineEmits(['update:modelValue']);
const magnifyBottom = ref(false);
const phoneUtil = PhoneNumberUtil.getInstance();
const defaultArea = '+86';
const formValue = ref('');
const validMessage = ref(false);
const showMagnify = ref(false);
const phoneNumberModel = computed({
  get() {
    let str = formValue.value.replace(/\s*/g, '');
    for (let index = 0; index < props.areaOpts.length; index++) {
      let value = '\\' + props.areaOpts[index].value;
      let regExp = new RegExp(value);
      let match = str.match(regExp);
      if (match && match.index == 0 && props.globalization) {
        str = str.replace(regExp, '');
      }
    }
    str = handleFormatValue(str);
    return str;
  },
  set(val) {
    if (val[0] == '+' || !props.globalization) {
      formValue.value = val;
    } else if (Number(val.replace(/\s*/g, ''))) {
      formValue.value = phoneArea.value + val.replace(/\s*/g, '');
    } else {
      formValue.value = phoneArea.value;
    }
  }
});
const phoneArea = computed({
  get() {
    let _phoneArea = defaultArea;
    for (let index = 0; index < props.areaOpts.length; index++) {
      let value = '\\' + props.areaOpts[index].value;
      let regExp = new RegExp(value);
      let match = formValue.value.match(regExp);
      if (match && match.index == 0) {
        _phoneArea = match[0];
        return _phoneArea;
      }
    }
    return _phoneArea;
  },
  set(val) {
    formValue.value = val + phoneNumberModel.value.replace(/\s*/g, '');
  }
});
watch([() => phoneNumberModel.value, () => phoneArea.value], () => {
  checkValidPhone();
});
watch(formValue, (val) => {
  emits('update:modelValue', val.replace(/\s*/g, ''));
});
function initData() {
  const val = props.modelValue;
  if (val[0] == '+') {
    const phoneData = phoneUtil.parse(val);
    phoneArea.value = '+' + phoneData.values_['1'];
    phoneNumberModel.value = String(phoneData.values_['2']);
  } else {
    phoneNumberModel.value = val;
  }
}
function checkValidPhone() {
  try {
    if (phoneNumberModel.value) {
      let phoneNumber = phoneNumberModel.value.replace(/\s*/g, '');
      let area = phoneArea.value.replace(/\+/g, '');
      let number = phoneUtil.parseAndKeepRawInput(
        phoneNumber,
        phoneUtil.getRegionCodeForCountryCode(area)
      );
      validMessage.value = !phoneUtil.isValidNumber(number);
    }
  } catch (error) {
    validMessage.value = true;
  }
}
function handleFormatValue(val) {
  let str = val.replace(/\s*/g, '');
  let formatValue = '';
  if (Number(str) || str == '+') {
    let arr = [];
    let first = str.slice(0, 3);
    if (first) {
      arr.push(first);
      let second = str.slice(3, 7);
      if (second) {
        arr.push(second);
        let last = str.slice(7, 11);
        if (last) {
          arr.push(last);
        }
      }
    }
    formatValue = arr.join(' ');
  } else {
    formatValue = '';
  }
  return formatValue;
}
function handleBlur() {
  showMagnify.value = false;
}
function handleFocus() {
  showMagnify.value = true;
}

const phoneNumberRef = ref(null);
function checkMagnifyPosition() {
  const pnRect = unref(phoneNumberRef).getBoundingClientRect();
  if (pnRect.top < 44) {
    magnifyBottom.value = true;
  } else {
    magnifyBottom.value = false;
  }
}
initData();
onMounted(() => {
  checkMagnifyPosition();
});
</script>
<style lang="scss">
.lc-phone-number {
  position: relative;
  &__magnify {
    position: absolute;
    bottom: 100%;
    left: 0;
    right: 0;
    padding: 10px;
    border-radius: 4px;
    word-break: break-word;
    background: #f6f6f6;
    color: #ff984c;
    font-size: 24px;
    line-height: 1;
    z-index: 9999;
    &-bottom {
      top: 100%;
      bottom: auto;
    }
  }
  &__error-message {
    position: absolute;
    top: 100%;
    left: 0;
    padding-top: 4px;
    color: var(--error-color);
    font-size: 12px;
    line-height: 1;
  }
}
.lc-phone-number__wrap {
  width: var(--width, 240px);
}
.lc-phone-number__content {
  position: relative;
  display: flex;
  .el-select {
    .el-input__inner {
      width: 100%;
    }
  }
  &__area {
    width: 85px;
    .el-select {
      width: 85px;
    }
  }
  &__globalization {
    margin-left: 5px;
    flex: 1;
    .el-input,
    .el-input__inner {
      width: 100% !important;
    }
  }
}
</style>
